home *** CD-ROM | disk | FTP | other *** search
- /* avltree.c - AVL tree processing functions */
-
- #include "avltree.h"
- #include <malloc.h>
- #include <stdio.h>
-
- #define die(x) {fprintf(stderr,"%s (%d): fatal error - %s\n",__FILE__,__LINE__,(x));exit(-1);}
-
- /* find_in_tree - find key in tree */
-
- avl_tree find_in_tree(key, t)
- char *key; avl_tree t; {
-
- avl_tree tp; /* pointer to current tree node */
- boolean found; /* has key been found? */
- int test; /* value of comparision */
- tp = t;
- found = FALSE;
- while (tp != NULL && !found) {
- test = strcmp(key,tp->avl_key);
- if (test == 0)
- found = TRUE;
- else if (test < 0)
- tp = tp->avl_left;
- else if (test > 0)
- tp = tp->avl_right;
- else
- die("Unknown int from strcmp in find_in_tree");
- }
- return(tp);
- }
-
- /* init_tree (local) - set up one node AVL tree */
-
- static avl_tree init_tree(key, data)
- char *key, *data; {
-
- avl_tree new_tree;
-
- new_tree = (avl_tree) calloc(1,sizeof(struct avl_node));
- new_tree->avl_left = new_tree->avl_right = NULL;
- new_tree->_avl_bf = 0;
- new_tree->avl_key = key;
- new_tree->avl_data = data;
- return(new_tree);
- }
-
- /* locate_ins_point (local) - find point to add node to AVL tree */
-
- static void locate_ins_point(key, data, t, pivot, pivot_parent, previous)
- char *key, *data; avl_tree t, *pivot, *pivot_parent, *previous; {
-
- avl_tree current;
- boolean found;
- int test;
-
- *pivot_parent = *previous = NULL;
- *pivot = current = t;
- found = FALSE;
-
- /* search t for insertion point */
-
- while (current != NULL && !found) {
-
- /* check for pivot */
-
- if (current->_avl_bf != 0) {
- *pivot = current;
- *pivot_parent = *previous;
- }
-
- /* see what direction to go */
-
- test = strcmp(key, current->avl_key);
-
- /* we shouldn't get here */
-
- if (test == 0) {
- found = TRUE;
- current->avl_data = data;
- }
-
- /* left branch? */
-
- else if (test < 0) {
- *previous = current;
- current = current->avl_left;
- }
-
- /* right branch? */
-
- else if (test > 0) {
- *previous = current;
- current = current->avl_right;
- }
-
- else
- die("Unknown int from strcmp in locate_ins_point");
- }
- }
-
- /*
- * adj_bf (local) - adjust balance factors in AVL tree
- * from pivot down. Returns delta_bf.
- */
-
- static int adj_bf(pivot, heavy_side, new_node)
- avl_tree pivot, *heavy_side, new_node; {
-
- avl_tree current;
- int test, delta_bf;
-
- test = strcmp(new_node->avl_key, pivot->avl_key);
- if (test > 0) {
- *heavy_side = current = pivot->avl_right;
- delta_bf = -1;
- }
- else {
- *heavy_side = current = pivot->avl_left;
- delta_bf = 1;
- }
-
- while (current != new_node) {
-
- test = strcmp(new_node->avl_key, current->avl_key);
-
- /* height of right increases by 1 */
- if (test > 0) {
- current->_avl_bf = -1;
- current = current->avl_right;
- }
-
- /* height of left increases by 1 */
- else {
- current->_avl_bf = 1;
- current = current->avl_left;
- }
- }
- pivot->_avl_bf += delta_bf;
- return(delta_bf);
- }
-
- /* ll rotate (local) - perform LL rotation and return new root */
-
- static avl_tree ll_rotate(pivot)
- avl_tree pivot; {
-
- avl_tree heavy_side;
-
- heavy_side = pivot->avl_left;
- pivot->avl_left = heavy_side->avl_right;
- heavy_side->avl_right = pivot;
- pivot->_avl_bf = 0;
- return(heavy_side);
- }
-
- /* lr rotate (local) - perform LR rotation and return new root */
-
- static avl_tree lr_rotate(pivot)
- avl_tree pivot; {
-
- avl_tree new_root, heavy_side;
-
- heavy_side = pivot->avl_left;
- new_root = heavy_side->avl_right;
- heavy_side->avl_right = new_root->avl_left;
- pivot->avl_left = new_root->avl_right;
- new_root->avl_left = heavy_side;
- new_root->avl_right = pivot;
-
- switch(new_root->_avl_bf) {
-
- case 1: /* LR(b) */
- pivot->_avl_bf = -1;
- heavy_side->_avl_bf = 0;
- break;
-
- case -1: /* LR(c) */
- heavy_side->_avl_bf = 1;
- pivot->_avl_bf = 0;
- break;
-
- case 0: /* LR(a) */
- pivot->_avl_bf = 0;
- heavy_side->_avl_bf = 0;
- break;
-
- default:
- die("bad balance factor in LR rotate");
- }
- new_root->_avl_bf = 0;
- return(new_root);
- }
-
- /* rr rotate (local) - perform RR rotation and return new root */
-
- static avl_tree rr_rotate(pivot)
- avl_tree pivot; {
-
- avl_tree heavy_side;
-
- heavy_side = pivot->avl_right;
- pivot->avl_right = heavy_side->avl_left;
- heavy_side->avl_left = pivot;
- pivot->_avl_bf = 0;
- heavy_side->_avl_bf = 0;
- return(heavy_side);
- }
-
- /* rl rotate (local) - perform the RL rotation and return the new root */
-
- static avl_tree rl_rotate(pivot)
- avl_tree pivot; {
-
- avl_tree new_root, heavy_side;
-
- heavy_side = pivot->avl_right;
- new_root = heavy_side->avl_left;
- heavy_side->avl_left = new_root->avl_right;
- pivot->avl_right = new_root->avl_left;
- new_root->avl_right = heavy_side;
- new_root->avl_left = pivot;
-
- switch(new_root->_avl_bf) {
-
- case -1: /* RL(b) */
- pivot->_avl_bf = 1;
- heavy_side->_avl_bf = 0;
- break;
-
- case 1: /* RL(c) */
- heavy_side->_avl_bf = -1;
- pivot->_avl_bf = 0;
- break;
-
- case 0: /* RL(a) */
- pivot->_avl_bf = 0;
- heavy_side->_avl_bf = 0;
- break;
-
- default:
- die("bad balance factor in RL rotate");
- }
- new_root->_avl_bf = 0;
- return(new_root);
- }
-
- /* AVL insert - add node to AVL tree. Pointer to tree node is returned */
-
- avl_tree avl_insert(key, data, t)
- char *key, *data; avl_tree *t; {
-
- avl_tree pivot, heavy_side, new_root, pivot_parent, previous, new_node;
- boolean found;
- int delta_bf;
-
- /* special case - empty tree */
-
- if (*t == NULL) {
- *t = init_tree(key, data);
- return(*t);
- }
-
- /* find insertion point and create node */
-
- locate_ins_point(key, data, *t, &pivot, &pivot_parent, &previous);
- new_node = init_tree(key, data);
-
- /* insert node */
-
- if (strcmp(key, previous->avl_key) < 0)
- previous->avl_left = new_node;
- else
- previous->avl_right = new_node;
-
- delta_bf = adj_bf(pivot, &heavy_side, new_node);
-
- if (pivot->_avl_bf >= 2 || pivot->_avl_bf <= -2) {
-
- /* left imbalance */
-
- if (delta_bf == 1)
- if (heavy_side->_avl_bf == 1)
- new_root = ll_rotate(pivot);
- else
- new_root = lr_rotate(pivot);
-
- /* right imbalance */
-
- else
- if (heavy_side->_avl_bf == -1)
- new_root = rr_rotate(pivot);
- else
- new_root = rl_rotate(pivot);
-
- /* relink balanced subtree */
-
- if (pivot_parent == NULL)
- *t = new_root;
- else if (pivot == pivot_parent->avl_left)
- pivot_parent->avl_left = new_root;
- else if (pivot == pivot_parent->avl_right)
- pivot_parent->avl_right = new_root;
- else
- die("lost subtree in AVL insert");
- }
- return(new_node);
- }
-
- /* sideview - output tree recursively */
-
- void sideview(depth, t)
- int depth; avl_tree t; {
-
- register int i;
-
- if (t != NULL) {
- sideview(depth + 1, t->avl_right);
- for (i = 0; i < 2 * depth; i++) {
- putchar(' ');
- }
- printf("%d BF=%d %s:%s\n", depth, t->_avl_bf,t->avl_key, t->avl_data);
- sideview(depth + 1, t->avl_left);
- }
- }
-
-
-
-